
fn parse_input() -> Vec<Vec<u8>> {
    let input = include_str!("../input.txt");
    input
        .lines()
        .map(|line| -> Vec<u8> {
            line
                .chars()
                .map(|c| c as u8 - ('0' as u8))
                .collect()
        })
        .collect()
}

fn part1() {
    let grid = parse_input();
    let height = grid.len();
    let width  = grid[0].len();

    let mut visible_size = 2 * (height + width - 2);
    for row in 1..(height - 1) {
        for col in 1..(width - 1) {
            let curr_height = grid[row][col];
            // Check left
            if grid[row][0..col].into_iter().all(|&height| height < curr_height) ||
               grid[row][(col + 1)..].into_iter().all(|&height| height < curr_height) ||
               (0..row).into_iter().all(|r| grid[r][col] < curr_height) ||
               (row+1..height).into_iter().all(|r| grid[r][col] < curr_height) 
            {
                visible_size += 1;
            }
        }
    }

    println!("Part 1: {}", visible_size);
}

fn part2() {
    // stop if you reach an edge or at the first tree that 
    // is the same height or taller than the tree under consideration.
    let grid = parse_input();
    let height = grid.len();
    let width  = grid[0].len();

    let mut max_score = 0;
    for row in 1..(height - 1) {
        for col in 1..(width - 1) {
            let curr_height = grid[row][col];

            let left_size = {
                let left_size = 
                    grid[row][0..col].iter().rev().take_while(|&&height| height < curr_height).count();
                // Block one
                left_size + if col > left_size { 1 } else { 0 }
            };

            let right_size = {
                let right_size = 
                    grid[row][col+1..width].iter().take_while(|&&height| height < curr_height).count();
                right_size + if (width - 1 - col) > right_size { 1 } else { 0 }
            };

            let up_size = {
                let up_size = 
                    (0..row).into_iter().rev().take_while(|&r| grid[r][col] < curr_height).count();
                up_size + if row > up_size { 1 } else { 0 }
            };

            let down_size = {
                let down_size = 
                    (row+1..height).into_iter().take_while(|&r| grid[r][col] < curr_height).count();
                down_size + if (height - row - 1) > down_size { 1 } else { 0 }
            };

            let score = left_size * right_size * up_size * down_size;
            if max_score < score {
                max_score = score;
            }
        }
    }

    println!("Part 2: {}", max_score);
}

fn main() {
    part1();
    part2();
}
